import binascii

from PySide6.QtGui import QIcon

import ui.resource_rc

from PySide6.QtWidgets import QMainWindow, QFileDialog
from PySide6.QtSerialPort import QSerialPortInfo, QSerialPort
from PySide6.QtCore import Slot, Signal, QByteArray, QTimer

import datetime

from ui.ui import Ui_SerialTools
from codes.serial_model import SerialModel


class SerialTools(QMainWindow, Ui_SerialTools):
    signal_open_serial = Signal(tuple)
    signal_close_serial = Signal()
    signal_send_msg = Signal(QByteArray)

    def __init__(self):
        super().__init__()
        self.setupUi(self)
        self.setWindowTitle("串口调试工具")

        self.open_icon = QIcon(":/image/opened.png")
        self.close_icon = QIcon(":/image/closed.png")
        self.open_close.setIcon(self.close_icon)

        self.rx_count = 0
        self.tx_count = 0

        # 初始化获取计算机串口资源，并显示
        self.slot_update_ports()
        self.refresh_ports.clicked.connect(self.slot_update_ports)

        # 初始化常用波特率并显示
        baud_rate_list = [110, 300, 600, 1200, 2400, 4800, 9600, 14400, 19200, 38400, 43000, 57600, 76800, 115200,
                          128000, 230400, 256000, 460800, 921600, 1000000, 2000000, 3000000]
        self.baud_rate.addItem("自定义", 0)
        for baud_rate in baud_rate_list:
            self.baud_rate.addItem(str(baud_rate), baud_rate)
        self.baud_rate.setCurrentText("115200")

        # 初始化停止位，并显示
        stop_bits_list = ["1", "1.5", "2"]
        q_stop_bits_list = [QSerialPort.StopBits.OneStop,
                            QSerialPort.StopBits.OneAndHalfStop,
                            QSerialPort.StopBits.TwoStop]
        for stop_bits, q_stop_bits in zip(stop_bits_list, q_stop_bits_list):
            self.stop_bits.addItem(stop_bits, q_stop_bits)
        self.stop_bits.setCurrentText("1")

        # 初始化数据位，并显示
        data_bits_list = ["8", "7", "6", "5"]
        q_data_bits_list = [QSerialPort.DataBits.Data8,
                            QSerialPort.DataBits.Data7,
                            QSerialPort.DataBits.Data6,
                            QSerialPort.DataBits.Data5]
        for data_bits, q_data_bits in zip(data_bits_list, q_data_bits_list):
            self.data_bits.addItem(data_bits, q_data_bits)
        self.data_bits.setCurrentText("8")

        # 初始化校验位，并显示
        parity_list = ["None", "Odd", "Even"]
        q_parity_list = [QSerialPort.Parity.NoParity,
                         QSerialPort.Parity.OddParity,
                         QSerialPort.Parity.EvenParity]
        for parity, q_parity in zip(parity_list, q_parity_list):
            self.parity.addItem(parity, q_parity)

        self.parity.setCurrentText("None")

        # 初始化流控，并显示
        flow_control_list = ["None", "RTS/CTS", "XON/XOFF"]
        q_flow_control_list = [QSerialPort.FlowControl.NoFlowControl,
                               QSerialPort.FlowControl.HardwareControl,
                               QSerialPort.FlowControl.SoftwareControl]
        for flow_control, q_flow_control in zip(flow_control_list, q_flow_control_list):
            self.flow_control.addItem(flow_control, q_flow_control)

        self.flow_control.setCurrentText("None")

        self.open_close.clicked.connect(self.slot_open_close_serial)  # 连接信号与槽，响应打开/关闭串口按钮动作
        self.recv_clear.clicked.connect(self.slot_clear_recv_text)  # 连接信号与槽，响应清除接收按钮动作
        self.single_send_bt.clicked.connect(self.slot_single_send_msg)  # 连接信号与槽，响应单条发送按钮动作
        self.single_send_clear.clicked.connect(self.slot_clear_single_send_text)  # 连接信号与槽，响应清除单条发送按钮动作
        self.single_hex_send.toggled.connect(self.slot_single_hex_input)  # 连接信号与槽，响应单条Hex输入按钮动作
        self.single_ascii_send.toggled.connect(self.slot_single_ascii_input)  # 连接信号与槽，响应单条ASCII输入按钮动作


        # 初始化单条发送定时器
        self.single_timer = QTimer()
        self.single_timer.timeout.connect(self.slot_single_send_msg)
        self.single_send_timer_enable.toggled.connect(self.slot_enable_single_timer)  # 连接信号与槽，响应单条定时发送动作

        self.multi_enable_list = [self.multi_1_enable, self.multi_2_enable, self.multi_3_enable,
                                  self.multi_4_enable, self.multi_5_enable, self.multi_6_enable,
                                  self.multi_7_enable, self.multi_8_enable, self.multi_9_enable,
                                  self.multi_10_enable]
        self.multi_text_list = [self.multi_1_send_text, self.multi_2_send_text, self.multi_3_send_text,
                                self.multi_4_send_text, self.multi_5_send_text, self.multi_6_send_text,
                                self.multi_7_send_text, self.multi_8_send_text, self.multi_9_send_text,
                                self.multi_10_send_text]

        self.multi_1_send_btn.clicked.connect(self.slot_multi_send_1)
        self.multi_2_send_btn.clicked.connect(self.slot_multi_send_2)
        self.multi_3_send_btn.clicked.connect(self.slot_multi_send_3)
        self.multi_4_send_btn.clicked.connect(self.slot_multi_send_4)
        self.multi_5_send_btn.clicked.connect(self.slot_multi_send_5)
        self.multi_6_send_btn.clicked.connect(self.slot_multi_send_6)
        self.multi_7_send_btn.clicked.connect(self.slot_multi_send_7)
        self.multi_8_send_btn.clicked.connect(self.slot_multi_send_8)
        self.multi_9_send_btn.clicked.connect(self.slot_multi_send_9)
        self.multi_10_send_btn.clicked.connect(self.slot_multi_send_10)

        self.multi_hex_send.toggled.connect(self.slot_multi_hex_input)
        self.multi_export.clicked.connect(self.slot_multi_export)
        self.multi_import.clicked.connect(self.slot_multi_import)

        # 初始化多条发送定时器
        self.multi_timer = QTimer()
        self.multi_timer.timeout.connect(self.slot_multi_send_msg)
        self.multi_send_timer_enable.toggled.connect(self.slot_enable_multi_timer)  # 连接信号与槽，响应多条定时发送动作

        # 初始化串口通讯Model
        self.serial_model = SerialModel(self)
        self.serial_model.start()
        self.serial_model.signal_open_result.connect(self.slot_open_result)  # 连接信号与槽，接收连接状态
        self.serial_model.signal_send_msg.connect(self.slot_recv_msg)  # 连接信号与槽，接收读取消息内容
        self.signal_open_serial.connect(self.serial_model.open_serial)  # 连接信号与槽，发送连接命令
        self.signal_close_serial.connect(self.serial_model.close_serial)  # 连接信号与槽，发送断开连接命令
        self.signal_send_msg.connect(self.serial_model.send_msg)  # 连接信号与槽，发送发送消息命令

    def closeEvent(self, event):
        if self.serial_model.isRunning() is True:
            self.serial_model.exit()
            self.serial_model.wait()

    @Slot()
    def slot_update_ports(self):
        ports = QSerialPortInfo.availablePorts()
        for port in ports:
            self.port_select.addItem(port.portName(), port)

    @Slot(bool)
    def slot_open_result(self, result):
        if result is True:
            self.open_close.setText("关闭串口")
            self.open_close.setIcon(self.open_icon)
        else:
            self.open_close.setText("打开串口")
            self.open_close.setIcon(self.close_icon)

    @Slot(bool)
    def slot_open_close_serial(self, checked):
        if checked is True:
            self.signal_open_serial.emit((self.port_select.currentData(),
                                          self.baud_rate.currentData(),
                                          self.stop_bits.currentData(),
                                          self.data_bits.currentData(),
                                          self.parity.currentData(),
                                          self.flow_control.currentData()))
        else:
            self.signal_close_serial.emit()

    @Slot(QByteArray)
    def slot_recv_msg(self, msg):
        # 更新接收字节计数
        self.rx_count += msg.count()
        self.rx_num.setText("RX: %d" % self.rx_count)

        # 判断是否显示时间戳
        if self.recv_time_stamp.isChecked():
            self.recv_text.append(
                "<font color=\"#DC143C\", size=\"4\">[%s]</font>" % datetime.datetime.now().strftime('%F %T'))

        # 判断是否为Hex显示
        if self.recv_hex.isChecked() is True:
            msg = self.__ascii_to_hex(str(msg))
            self.recv_text.append("%s\n" % msg)
            return

        # 直接显示
        self.recv_text.append("%s\n" % bytes(msg.data()).decode('utf-8'))

    @Slot()
    def slot_clear_recv_text(self):
        self.recv_text.clear()

        self.rx_count = 0
        self.rx_num.setText("RX: %d" % self.rx_count)

    @Slot()
    def slot_single_send_msg(self):
        msg = self.single_send_text.toPlainText()
        if not msg:
            return

        # 如果为16进制发送，则先转为ASCII
        if self.single_hex_send.isChecked() is True:
            msg = self.__hex_to_ascii(msg)

        self.__send_msg(msg)

    @Slot()
    def slot_clear_single_send_text(self):
        self.single_send_text.clear()

    @Slot(bool)
    def slot_enable_single_timer(self, checked):
        if checked is True:
            self.single_send__timer_cycle.setDisabled(True)
            self.single_timer.start(self.single_send__timer_cycle.value())
        else:
            self.single_send__timer_cycle.setDisabled(False)
            self.single_timer.stop()

    @Slot(bool)
    def slot_single_ascii_input(self, checked):
        if checked is True:
            hex_str = self.single_send_text.toPlainText()
            if not hex_str:
                return

            self.single_send_text.setText(self.__hex_to_ascii(hex_str))

    @Slot(bool)
    def slot_single_hex_input(self, checked):
        if checked is True:
            ascii_str = self.single_send_text.toPlainText()
            if not ascii_str:
                return

            self.single_send_text.setText(self.__ascii_to_hex(ascii_str))

    def __hex_to_ascii(self, hex_str):
        # 去除空格并转换为字节串
        byte_str = binascii.unhexlify(hex_str.replace(' ', ''))

        # 将字节串解码为 ASCII 字符串
        ascii_str = byte_str.decode('ascii')

        return ascii_str

    def __ascii_to_hex(self, ascii_str):
        # 将 ASCII 字符串转换为字节串
        byte_str = ascii_str.encode()

        # 将字节串转换为十六进制字符串
        hex_str = byte_str.hex()

        # 每两个字符用空格分隔
        hex_list = [hex_str[i:i + 2] for i in range(0, len(hex_str), 2)]
        hex_str = ' '.join(hex_list)

        # 每 4 个字节添加一个空格，形成美化输出
        hex_str = ' '.join([hex_str[i:i + 11] for i in range(0, len(hex_str), 11)])
        return hex_str

    def __send_msg(self, msg):
        if self.open_close.isChecked() is True:
            # 更新发送字节计数
            msg = QByteArray.fromStdString(msg)
            self.tx_count += msg.count()
            self.tx_num.setText("TX: %d" % self.tx_count)

            # 通知Model发送
            self.signal_send_msg.emit(msg)

    @Slot()
    def slot_multi_send_msg(self):
        hex_enable = self.multi_hex_send.isChecked()

        for multi_enable, multi_text in zip(self.multi_enable_list, self.multi_text_list):
            if multi_enable.isChecked() is True:
                msg = multi_text.text()
                if msg:
                    # 如果为16进制发送，则先转为ASCII
                    if hex_enable is True:
                        msg = self.__hex_to_ascii(msg)

                    self.__send_msg(msg)

    @Slot(bool)
    def slot_enable_multi_timer(self, checked):
        if checked is True:
            self.multi_send_timer_cycle.setDisabled(True)
            self.multi_timer.start(self.multi_send_timer_cycle.value())
        else:
            self.multi_send_timer_cycle.setDisabled(False)
            self.multi_timer.stop()

    @Slot(bool)
    def slot_multi_hex_input(self, checked):
        if checked is True:
            for multi_text in self.multi_text_list:
                text = multi_text.text()
                if text:
                    multi_text.setText(self.__ascii_to_hex(text))
        else:
            for multi_text in self.multi_text_list:
                text = multi_text.text()
                if text:
                    multi_text.setText(self.__hex_to_ascii(text))

    @Slot()
    def slot_multi_send_1(self):
        msg = self.multi_1_send_text.text()
        if not msg:
            return

        # 如果为16进制发送，则先转为ASCII
        if self.multi_hex_send.isChecked() is True:
            msg = self.__hex_to_ascii(msg)

        self.__send_msg(msg)

    @Slot()
    def slot_multi_send_2(self):
        msg = self.multi_2_send_text.text()
        if not msg:
            return

        # 如果为16进制发送，则先转为ASCII
        if self.multi_hex_send.isChecked() is True:
            msg = self.__hex_to_ascii(msg)

        self.__send_msg(msg)

    @Slot()
    def slot_multi_send_3(self):
        msg = self.multi_3_send_text.text()
        if not msg:
            return

        # 如果为16进制发送，则先转为ASCII
        if self.multi_hex_send.isChecked() is True:
            msg = self.__hex_to_ascii(msg)

        self.__send_msg(msg)

    @Slot()
    def slot_multi_send_4(self):
        msg = self.multi_4_send_text.text()
        if not msg:
            return

        # 如果为16进制发送，则先转为ASCII
        if self.multi_hex_send.isChecked() is True:
            msg = self.__hex_to_ascii(msg)

        self.__send_msg(msg)

    @Slot()
    def slot_multi_send_5(self):
        msg = self.multi_5_send_text.text()
        if not msg:
            return

        # 如果为16进制发送，则先转为ASCII
        if self.multi_hex_send.isChecked() is True:
            msg = self.__hex_to_ascii(msg)

        self.__send_msg(msg)

    @Slot()
    def slot_multi_send_6(self):
        msg = self.multi_6_send_text.text()
        if not msg:
            return

        # 如果为16进制发送，则先转为ASCII
        if self.multi_hex_send.isChecked() is True:
            msg = self.__hex_to_ascii(msg)

        self.__send_msg(msg)

    @Slot()
    def slot_multi_send_7(self):
        msg = self.multi_7_send_text.text()
        if not msg:
            return

        # 如果为16进制发送，则先转为ASCII
        if self.multi_hex_send.isChecked() is True:
            msg = self.__hex_to_ascii(msg)

        self.__send_msg(msg)

    @Slot()
    def slot_multi_send_8(self):
        msg = self.multi_8_send_text.text()
        if not msg:
            return

        # 如果为16进制发送，则先转为ASCII
        if self.multi_hex_send.isChecked() is True:
            msg = self.__hex_to_ascii(msg)

        self.__send_msg(msg)

    @Slot()
    def slot_multi_send_9(self):
        msg = self.multi_9_send_text.text()
        if not msg:
            return

        # 如果为16进制发送，则先转为ASCII
        if self.multi_hex_send.isChecked() is True:
            msg = self.__hex_to_ascii(msg)

        self.__send_msg(msg)

    @Slot()
    def slot_multi_send_10(self):
        msg = self.multi_10_send_text.text()
        if not msg:
            return

        # 如果为16进制发送，则先转为ASCII
        if self.multi_hex_send.isChecked() is True:
            msg = self.__hex_to_ascii(msg)

        self.__send_msg(msg)

    @Slot()
    def slot_multi_export(self):
        file_name, _ = QFileDialog.getSaveFileName(self, 'Save File', '', 'Text Files (*.txt)')
        if file_name:
            with open(file_name, 'w') as f:
                item_list = []
                for multi_enable, multi_text in zip(self.multi_enable_list, self.multi_text_list):
                    item_list.append(','.join([str(multi_enable.isChecked()), multi_text.text()]))

                f.write('\n'.join(item_list))

    @Slot()
    def slot_multi_import(self):
        file_name, _ = QFileDialog.getOpenFileName(self, 'Save File', '', 'Text Files (*.txt)')
        if file_name:
            with open(file_name, 'r') as f:
                item_list = f.read()
                item_list = item_list.split('\n')
                for item, multi_enable, multi_text in zip(item_list, self.multi_enable_list, self.multi_text_list):
                    item = item.split(',')
                    print(item)
                    multi_enable.setChecked(True if (item[0] == 'True') else False)
                    multi_text.setText(item[1])
